package com.sec.android.app.myfiles.module.cloud;

import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.format.Formatter;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.samsung.android.sdk.slinkcloud.CloudGatewayConstants;
import com.samsung.android.sdk.slinkcloud.CloudGatewayDeviceInfoUtils;
import com.samsung.android.sdk.slinkcloud.CloudGatewaySignInUtils;
import com.samsung.android.sdk.slinkcloud.CloudGatewayStorageUtils;
import com.sec.android.app.myfiles.R;
import com.sec.android.app.myfiles.dialog.UnableToAccessServerDialogFragment;
import com.sec.android.app.myfiles.dialog.UpdateDialogFragment;
import com.sec.android.app.myfiles.facade.MyFilesFacade;
import com.sec.android.app.myfiles.facade.cmd.CopyMoveCmd;
import com.sec.android.app.myfiles.facade.cmd.SpinnerProgressCmd;
import com.sec.android.app.myfiles.feature.CloudMgr;
import com.sec.android.app.myfiles.feature.DragAndDropMgr;
import com.sec.android.app.myfiles.feature.cloud.AbsCloudImp;
import com.sec.android.app.myfiles.fragment.AbsMyFilesFragment;
import com.sec.android.app.myfiles.fragment.home.HomeFragment;
import com.sec.android.app.myfiles.fragment.home.HomeFragmentItem;
import com.sec.android.app.myfiles.info.AppConstants;
import com.sec.android.app.myfiles.info.AppConstants.StoragePath;
import com.sec.android.app.myfiles.info.AppFeatures;
import com.sec.android.app.myfiles.listener.ConnectionChangeReceiver;
import com.sec.android.app.myfiles.listener.ListenerMgr;
import com.sec.android.app.myfiles.log.Log;
import com.sec.android.app.myfiles.module.abstraction.FileRecord;
import com.sec.android.app.myfiles.module.abstraction.FileRecord.CloudType;
import com.sec.android.app.myfiles.module.abstraction.FileRecord.StorageType;
import com.sec.android.app.myfiles.navigation.NavigationInfo;
import com.sec.android.app.myfiles.navigation.NavigationManager;
import com.sec.android.app.myfiles.operation.FileOperator;
import com.sec.android.app.myfiles.update.APKDownloadManager;
import com.sec.android.app.myfiles.update.UpdateChecker;
import com.sec.android.app.myfiles.util.StorageMonitor;
import com.sec.android.app.myfiles.util.UiUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;

public class CloudFileHomeItem extends HomeFragmentItem
        implements ConnectionChangeReceiver.OnConnectionBroadcast, CloudMgr.CloudStateListener {
    private CloudFileRecord mGoogleDriveRecord;
    private CloudFileRecord mSamsungDriveRecord;
    private boolean mCloudItemEnabled = true;
    private ListenerMgr mListenerMgr;
    private CloudMgr mCloudMgr;
    private TextView mCloudHeader;
    private DragAndDropMgr mDragDrop;

    public CloudFileHomeItem(Context context, HomeFragment fragment) {
        super(context, fragment);

        mCloudMgr = CloudMgr.getInstance(context);
        mCloudMgr.addListener(this);
        Collection<AbsCloudImp> cloudImpList = CloudMgr.getInstance(mContext).getCloudImpList().values();
        for (AbsCloudImp cloudImp : cloudImpList) {
            final CloudType cloudType = cloudImp.getCloudType();
            if (mCloudMgr.isAccountRetrieved(cloudType)) {
                updateCloudItem(cloudType);
            }
            if (mCloudMgr.isSignedIn(cloudType)) {
                UpdateQuotaThread updateQuotaThread = new UpdateQuotaThread(mContext.getApplicationContext(), mCloudMgr, cloudType);
                updateQuotaThread.start();
            }
        }

        mListenerMgr = new ListenerMgr();
        mListenerMgr.addListener(new ConnectionChangeReceiver(mContext, this, ListenerMgr.LifeCycle.CREATE, ListenerMgr.LifeCycle.DESTROY));
        mListenerMgr.notifyCreate();
    }

    private static class UpdateQuotaThread extends Thread {
        private final Context mApplicationContext;
        private final CloudMgr mCloudMgr;
        private final CloudType mCloudType;

        private UpdateQuotaThread(Context applicationContext, CloudMgr cloudMgr, CloudType cloudType) {
            this.mApplicationContext = applicationContext;
            this.mCloudMgr = cloudMgr;
            this.mCloudType = cloudType;
        }

        @Override
        public void run() {
            UiUtils.updateQuota(mApplicationContext, mCloudMgr, mCloudType);
        }
    }

    @Override
    protected void setItemEnabled(boolean enabled) {
        Log.d(this, "setItemEnabled " + enabled);
        mCloudItemEnabled = enabled;
        updateCloudVisibility();
    }

    private void updateCloudItem(final CloudType cloudType) {
        if (mFragment.isAdded()) {
            int viewId = getCloudViewId(cloudType);
            View itemView = mFragment.getView().findViewById(viewId);
            if (itemView != null) {
                if (mCloudMgr.isAccountRetrieved(cloudType)) {
                    int deviceId = mCloudMgr.getDeviceId(cloudType);
                    setItemEnabled(true);
                    switch (viewId) {
                        case R.id.cloud_storage_google_drive:
                            mGoogleDriveRecord.setDeviceId(deviceId);
                            break;
                        case R.id.cloud_storage_samsung_drive:
                            mSamsungDriveRecord.setDeviceId(deviceId);
                            break;
                        default:
                            break;
                    }
                } else {
                    Log.d(this, "Devices table doesn't have rows");
                    setItemEnabled(false);
                }
                updateLoginStatus(itemView, cloudType);
            }
        }
    }

    private int getCloudViewId(CloudType cloudType) {
        int ret = -1;
        switch (cloudType) {
            case GoogleDrive:
                ret = R.id.cloud_storage_google_drive;
                break;
            case SamsungDrive:
                ret = R.id.cloud_storage_samsung_drive;
                break;
            default:
                Log.e(this, "getCloudViewId() - cloud type(" + cloudType + ") was not proper");
                break;
        }
        return ret;
    }

    private void updateCloudVisibility() {
        if (mItemList != null) {
            NavigationManager navigationMgr = NavigationManager.getInstance(mFragment.getProcessId());
            NavigationInfo curInfo = navigationMgr.getCurInfo();
            boolean normalMode = !((curInfo != null) && (curInfo.isPickerMode() || curInfo.isCreateDocument()));
            boolean selectDstMode = ((curInfo != null) && curInfo.isSelectOpDestination());
            boolean selectMode = (curInfo != null) && ((curInfo.getCurFragment() != null) && (curInfo.getCurFragment().getActionModeType() != AbsMyFilesFragment.ActionModeType.NORMAL));
            boolean isPreview = (curInfo != null) && (curInfo.getNavigationMode() == NavigationInfo.NavigationMode.Preview_compress_item);

            int nVisibility = normalMode ? View.VISIBLE : View.GONE;

            mCloudHeader = (TextView) mRootView.findViewById(R.id.home_cloud_header);
            setViewVisibility(mCloudHeader, nVisibility);

            boolean networkOn = true;
            if (!AppFeatures.NO_SUPPORT_CLOUD && (nVisibility == View.VISIBLE) && selectDstMode) {
                networkOn = UiUtils.isNetworkOn(mContext);
                Log.d(this, "updateCloudVisibility : " + selectDstMode + " " + networkOn + " " + mCloudItemEnabled);
            }

            boolean isAvailableFreeSpace = StorageMonitor.getDeviceStorageFreeSpace() > AppConstants.AVAILABLE_DEVICE_STORAGE_FREE_SPACE;

            for (HomeItemInfo h : mItemList) {
                setViewVisibility(h.itemView, nVisibility);
                setChildItemEnabled(h.itemView, networkOn && mCloudItemEnabled && !selectMode && !isPreview && isAvailableFreeSpace);
            }
        }
    }

    @Override
    protected void setListItem() {
        if (!AppFeatures.NO_SUPPORT_CLOUD) {
            mDragDrop = new DragAndDropMgr(mFragment, StorageType.Home);
            mGoogleDriveRecord = setItem(StoragePath.GOOGLE_DRIVE_FOLDER, AppConstants.CloudType.GOOGLE_DRIVE, R.id.cloud_storage_google_drive, R.drawable.my_files_ic_drive, R.color.home_icon_google_drive_color, R.string.google_drive);
            if (AppFeatures.isSupportSamsungDrive()) {
                mSamsungDriveRecord = setItem(StoragePath.SAMSUNG_DRIVE_FOLDER, AppConstants.CloudType.SAMSUNG_DRIVE, R.id.cloud_storage_samsung_drive, R.drawable.my_files_ic_cloud, R.color.home_icon_samsung_drive_color, UiUtils.getSamsungDriveString());
                if (mFragment.getView() != null) {
                    setViewVisibility(mFragment.getView().findViewById(R.id.cloud_divider), View.VISIBLE);
                }
            }
        }
        updateCloudVisibility();
    }

    private CloudFileRecord setItem(String path, String cloudName, int itemRes, int iConRes, int iconColorRes, int strRes) {
        CloudFileRecord ret = (CloudFileRecord) FileRecord.createFileRecord(StorageType.Cloud, path);

        if (ret != null) {
            ret.setFileId(CloudFileRecord.CLOUD_ROOT);
            CloudItemClickListener onclick = new CloudItemClickListener(ret, "Cloud-" + cloudName);
            HomeItemInfo item = new HomeItemInfo(0, itemRes, iConRes, iconColorRes, 0, strRes, onclick);

            mItemList.add(item);
            mDragDrop.attachDragListenerToView(item.itemView);
        }

        return ret;
    }

    @Override
    protected void _onResume() {
        setContentDescription(mCloudHeader, R.string.cloud);
    }

    private void updateLoginStatus(View itemView, CloudType cloudType) {
        TextView signedInfoView = (TextView) itemView.findViewById(R.id.home_list_item_text_second);
        if (mCloudMgr.isAccountRetrieved(cloudType)) {
            String signedUserId = mCloudMgr.getUserId(cloudType);
            if (signedUserId == null || signedUserId.isEmpty()) {
                signedInfoView.setText(mCloudMgr.isSignedIn(cloudType) ? R.string.retrieving_account : R.string.not_signed_in);
            } else {
                ensureSizeView(signedInfoView, mCloudMgr.getTotalSize(cloudType), mCloudMgr.getUsedSize(cloudType));

                long freeSpace = mCloudMgr.getTotalSize(cloudType) - mCloudMgr.getUsedSize(cloudType);
                if (mFragment.getNavigationInfo().getNavigationMode() == NavigationInfo.NavigationMode.Select_optimize_storage_backup_destination) {
                    ArrayList<FileRecord> selectedFiles = CopyMoveCmd.getSelectedList();
                    if (selectedFiles != null) {
                        long selectedFilesSize = 0;
                        for (FileRecord rec : selectedFiles) {
                            if (rec != null) {
                                selectedFilesSize += rec.getSize();
                            }
                        }
                        if (selectedFilesSize > freeSpace) {
                            itemView.setEnabled(false);
                            itemView.setAlpha(0.4f);
                        } else {
                            itemView.setEnabled(true);
                            itemView.setAlpha(1.0f);
                        }
                    }
                }
            }
        } else {
            signedInfoView.setText(R.string.not_signed_in);
        }
    }

    @Override
    protected void _onDestroy() {
        if (mCloudMgr != null && mListenerMgr != null) {
            mCloudMgr.removeListener(this);
            mListenerMgr.notifyDestroy();
        }
    }

    @Override
    public void onConnect() {
        updateCloudVisibility();
    }

    @Override
    public void onDisconnect() {
        updateCloudVisibility();
    }

    @Override
    public void onCloudInit() {
        HashMap<CloudType, AbsCloudImp> cloudList = CloudMgr.getInstance(mContext).getCloudImpList();
        Collection<AbsCloudImp> cloudImpList = cloudList.values();

        for (AbsCloudImp cloudImp : cloudImpList) {
            updateCloudItem(cloudImp.getCloudType());
        }
    }

    @Override
    public void onAccountChanged(CloudType cloudType) {
        // TODO : Change this method to update the changed account only
        updateCloudItem(cloudType);
    }

    public class CloudItemClickListener extends HomeItemClickListener implements UpdateChecker.StubUpdateCheckListener {
        int mCurrentCloud = 0;

        public CloudItemClickListener(FileRecord record, String loggingString) {
            super(record, loggingString);
        }

        private boolean needCloudLogin(View view) {
            boolean bRet = false;

            TextView tv = (TextView) view.findViewById(R.id.home_list_item_text_second);
            if ((tv != null) && (tv.getText()).equals(mContext.getString(R.string.not_signed_in))) {
                String storageType = null;
                int deviceId = 0, loginPos = 0;
                switch (mCurrentCloud) {
                    case R.string.google_drive:
                        storageType = AppConstants.CloudType.GOOGLE_DRIVE;
                        deviceId = mGoogleDriveRecord.getDeviceId();
                        loginPos = CloudMgr.MYFILES_GOOGLEDRIVE_LOGIN;
                        break;
                    case R.string.galaxy_drive:
                            /* FALL THROUGH */
                    case R.string.samsung_drive:
                        storageType = AppConstants.CloudType.SAMSUNG_DRIVE;
                        deviceId = mSamsungDriveRecord.getDeviceId();
                        loginPos = CloudMgr.MYFILES_SAMSUNGDRIVE_LOGIN;
                        break;
                    default:
                        Log.e(this, "Undefined cloud");
                        break;
                }

                Bundle resultBundle = CloudGatewayDeviceInfoUtils.getInstance(mContext).getVersatileInformation("READY_TO_LOGIN", deviceId);

                if (mContext.getApplicationContext() != null && ((resultBundle == null) || (resultBundle.getBoolean("result") == false))) {
                    UiUtils.showToast(mContext.getApplicationContext(), R.string.db_not_ready);
                } else {
                    if (!UiUtils.isNetworkOn(mContext)) {
                        UnableToAccessServerDialogFragment accessDialogFragment = UnableToAccessServerDialogFragment.getInstance(R.string.unable_to_connect_network, mFragment.getActivity());
                        if (accessDialogFragment != null) {
                            accessDialogFragment.showAllowingStateLoss(mFragment.getFragmentManager(), UnableToAccessServerDialogFragment.NETWORK_WARNING);
                        }
                    } else {
                        Intent intent = CloudGatewayStorageUtils.getInstance(mContext).createStorageSignInIntent(storageType);
                        intent.putExtra(CloudGatewayConstants.SLINK_UI_APP_THEME, true);

                        try {
                            if (mFragment.isAdded()) {
                                mFragment.startActivityForResult(intent, loginPos);
                            }
                        } catch (ActivityNotFoundException e) {
                            Log.e(this, "needCloudLogin: CloudGateWay Activity Not found");
                        }
                    }
                }
                bRet = true;
            }

            return bRet;
        }

        @Override
        public void onClick(View view) {
            if (UiUtils.isValidClick(view.getId())) {
                NavigationManager navigationMgr = NavigationManager.getInstance(mFragment.getProcessId());
                NavigationInfo curInfo = navigationMgr.getCurInfo();
                boolean selectDstMode = ((curInfo != null) && curInfo.isSelectOpDestination());
                boolean isWifiOnlyMode = CloudGatewaySignInUtils.getInstance(mContext).getWifiOnlyMode();
                boolean isWifiOn = UiUtils.isWifiOn(mContext);

                if (selectDstMode && !AppFeatures.NO_SUPPORT_CLOUD && isWifiOnlyMode && !isWifiOn) {
                    UnableToAccessServerDialogFragment netDialog = UnableToAccessServerDialogFragment.getInstance(R.string.unable_to_connect_wifi, mFragment.getActivity());
                    netDialog.showAllowingStateLoss(mFragment.getFragmentManager(), UnableToAccessServerDialogFragment.WIFI_WARNING);
                } else if (selectDstMode && view.getId() == getCloudViewId(CloudType.SamsungDrive)) {
                    CheckDrmAsyncTask task = new CheckDrmAsyncTask(mContext, mFragment, view, this);
                    task.execute();
                } else {
                    enterCloud(true, view);
                }
            }
        }

        View mView = null;

        public void enterCloud(boolean needVersionCheck, View view) {
            mView = view;

            if (mItemList != null) {
                for (HomeItemInfo homeItem : mItemList) {
                    if (homeItem.itemView.equals(view)) {
                        mCurrentCloud = homeItem.resString;
                        break;
                    }
                }
            }

            if (needVersionCheck) {
                Context appContext = mContext.getApplicationContext();
                if (APKDownloadManager.getInstance(appContext).getVersionChecking()) {
                    if (mCurrentCloud != 0) {
                        String cloudName = appContext.getResources().getString(mCurrentCloud);
                        String msg = appContext.getResources().getString(R.string.version_checking, cloudName);
                        Toast.makeText(appContext, msg, Toast.LENGTH_LONG).show();
                    }
                    Log.d(this, "Another window is checking version update");
                    return;
                }

                if (!APKDownloadManager.getInstance(appContext).showUpdateDialog(mFragment.getProcessId(), mFragment.getActivity(), mFragment.getFragmentManager(), this)) {
                    if (!needCloudLogin(view)) {
                        super.onClick(view);
                    }
                }
            } else {
                if (!needCloudLogin(view)) {
                    super.onClick(view);
                }
            }
        }

        @Override
        public void onUpdateCheckResult(boolean hasMyFilesUpdate, boolean hasCloudUpdate) {
            MyFilesFacade.execSpinnerProgress(mFragment.getProcessId(), mFragment.getActivity(), SpinnerProgressCmd.OperationProgress.DISMISS);
            Log.d(this, "update check result : MyFiles - " + hasMyFilesUpdate + ", Cloud - " + hasCloudUpdate);

            if (hasMyFilesUpdate || hasCloudUpdate) {
                UpdateDialogFragment.updateDialogShow(mFragment.getFragmentManager(), hasCloudUpdate);
            } else {
                APKDownloadManager.getInstance(mContext.getApplicationContext()).setVersionChecking(false);
                enterCloud(false, mView);
            }
        }
    }

    @Override
    protected void _onPause() {
    }

    public FileRecord getDriveRecord(int requestCode) {
        FileRecord ret = null;
        switch (requestCode) {
            case CloudMgr.MYFILES_GOOGLEDRIVE_LOGIN:
                ret = mGoogleDriveRecord;
                break;
            case CloudMgr.MYFILES_SAMSUNGDRIVE_LOGIN:
                ret = mSamsungDriveRecord;
                break;
        }
        return ret;
    }

    private void ensureSizeView(TextView sizeView, long totalSize, long usedSize) {
        StringBuilder size = new StringBuilder();
        size.append(Formatter.formatFileSize(mContext, usedSize))
                .append(" / ")
                .append(Formatter.formatFileSize(mContext, totalSize));

        if (sizeView != null) {
            sizeView.setText(size.toString());
        }
    }

    private static class CheckDrmAsyncTask extends AsyncTask<Void, Void, Integer> {

        private Context mContext;
        private AbsMyFilesFragment mFragment;
        private View mClickedCloudItemView;
        private CloudItemClickListener mCloudItemClickListener;

        public CheckDrmAsyncTask(Context context, AbsMyFilesFragment fragment, View clickedItemView,
                                 CloudItemClickListener listener) {
            mContext = context;
            mFragment = fragment;
            mClickedCloudItemView = clickedItemView;
            mCloudItemClickListener = listener;
        }

        @Override
        protected void onPreExecute() {
            MyFilesFacade.execSpinnerProgress(mFragment.getProcessId(), mFragment.getActivity(), SpinnerProgressCmd.OperationProgress.SHOW);
        }

        @Override
        protected Integer doInBackground(Void... params) {
            return CloudFileOperationImp.countDrmFilesInSource(mContext, CopyMoveCmd.getSelectedList());
        }

        @Override
        protected void onPostExecute(Integer countDrm) {
            MyFilesFacade.execSpinnerProgress(mFragment.getProcessId(), mFragment.getActivity(), SpinnerProgressCmd.OperationProgress.DISMISS);

            NavigationManager navigationMgr = NavigationManager.getInstance(mFragment.getProcessId());
            NavigationInfo curInfo = navigationMgr.getCurInfo();

            if (countDrm > 0) {
                NavigationInfo.NavigationMode mode = curInfo.getNavigationMode();
                FileOperator.Operation op = FileOperator.Operation.NONE;
                switch (mode) {
                    case Select_copy_destination:
                        op = FileOperator.Operation.COPY;
                        break;
                    case Select_move_destination:
                        op = FileOperator.Operation.MOVE;
                        break;
                    default:
                        break;
                }
                String message = UiUtils.getDrmWarningMessage(mContext, op, countDrm);
                if (mContext.getApplicationContext() != null && message != null) {
                    Toast.makeText(mContext.getApplicationContext(), message, Toast.LENGTH_LONG).show();
                }
            } else {
                mCloudItemClickListener.enterCloud(true, mClickedCloudItemView);
            }
        }
    }
}
